﻿///////////////////////////////////////////////////////////////////////////////////////////////////
// AmiBroker Plug-in SDK | Copyright © 2010 by Koistya `Navin | http://code.google.com/p/amibroker/
// ------------------------------------------------------------------------------------------------
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
// except in compliance with the License. You may obtain a copy of the License at:
// http://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing, software distributed under the
// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
// either express or implied. See the License for the specific language governing permissions and
// limitations under the License.
///////////////////////////////////////////////////////////////////////////////////////////////////

using System;
using System.Runtime.InteropServices;
using System.Drawing;
using System.Windows.Forms;

namespace AmiBrokerPlugin
{
    /// <summary>
    /// All public static methods of this class will be exported for use by AmiBroker
    /// </summary>
    public static partial class Plugin
    {
        #region Common Exported Functions

        /////////////////////////////////////////////////////////////////////////
        // COMMON EXPORTED FUNCTONS
        //
        // Each AmiBroker plug-in DLL must export the following
        // functions:
        // 1. GetPluginInfo	- called when DLL is loaded
        // 2. Init - called when AFL engine is being initialized 
        // 3. Release - called when AFL engine is being closed
        /////////////////////////////////////////////////////////////////////////

        /// <summary>
        /// Called when DLL is loaded
        /// </summary>
        public static int GetPluginInfo(ref PluginInfo pluginInfo)
        {
            // TODO: Insert information about the plugin
            pluginInfo.Name = "AmiBroker® data Plug-in";            // Name of the plug-in
            pluginInfo.Vendor = "AmiBroker.CodePlex.com";           // Vendor of the plug-in
            pluginInfo.Type = PluginType.Data;                      // Plug-in type. AFL, Data or Optimizer
            pluginInfo.Version = 10001;                             // Plug-in version. v1.0.0
            pluginInfo.IDCode = GetIDCode("AMIP");                  // Unique ID of the plug-in
            pluginInfo.Certificate = 0;                             // Is this plug-in certified by AmiBroker
            pluginInfo.MinAmiVersion = 387000;                      // Minimum supported version of AmiBroker
            pluginInfo.StructSize = Marshal.SizeOf(pluginInfo);     // Just keep it

            return 1;
        }

        /// <summary>
        /// Called when AFL engine is being initialized
        /// </summary>
        public static int Init()
        {
            // TODO: Add initialization logic here
            return 1;
        }

        /// <summary>
        /// Called when AFL engine is being closed
        /// </summary>
        public static int Release()
        {
            // TODO: Add cleanup logic here
            return 1;
        }

        #endregion

        #region AFL Exported Functions

        /////////////////////////////////////////////////////////////////////////
        // INDICATOR PLUGIN EXPORTED FUNCTIONS
        //
        // 1. GetFunctionTable - called when AFL engine is being initialized 
        // 1. SetSiteInteface - called when AFL engine is being initialized 
        //
        // Each function may be called multiple times.
        //
        // The order of calling functions during intialization is as follows:
        //
        // SetSiteInterface -> GetFunctionTable	-> Init -> 
        // ... normal work ....
        // Release
        //
        // This cycle may repeat multiple times
        /////////////////////////////////////////////////////////////////////////

        public static int GetFunctionTable(IntPtr functionTablePtr)
        {
            return 1;
        }

        public static int SetSiteInterface(IntPtr siteInterfacePtr)
        {
            return 1;
        }

        #endregion

        #region Data Exported Functions

        /// <summary>
        /// GetQuotesEx function is functional equivalent fo GetQuotes but
        /// handles new Quotation format with 64 bit date/time stamp and floating point volume/open int
        /// and new Aux fields
        /// it also takes pointer to context that is reserved for future use (can be null)
        /// Called by AmiBroker 5.27 and above 
        /// </summary>
        unsafe public static int GetQuotesEx(string ticker, Periodicity periodicity, int lastValid, int size, Quotation* quotes, GQEContext* context)
        {
            // TODO: Add logic here. Take a look at the demo below:

            //for (var i = 0; i < 5; i++)
            //{
            //    quotes[i].DateTime = PackDate(DateTime.Today.AddDays(i - 5));
            //    quotes[i].Price = 10;
            //    quotes[i].Open = 15;
            //    quotes[i].High = 16;
            //    quotes[i].Low = 9;
            //    quotes[i].Volume = 1000;
            //    quotes[i].OpenInterest = 0;
            //    quotes[i].AuxData1 = 0;
            //    quotes[i].AuxData2 = 0;
            //}
            //return 5;

            // return 'lastValid + 1' if no updates are found and you want to keep all existing records
            return lastValid + 1;
        }

        unsafe public delegate void* Alloc(uint size);

        ///// <summary>
        ///// GetExtra data is optional function for retrieving non-quotation data
        ///// </summary>
        public static AmiVar GetExtraData(string ticker, string name, int arraySize, Periodicity periodicity, Alloc alloc)
        {
            return new AmiVar();
        }

        /// <summary>
        /// Configure function is called when user presses "Configure" button in File->Database Settings
        /// </summary>
        /// <param name="path">Path to AmiBroker database</param>
        /// <param name="site">A pointer to <see cref="AmiBrokerPlugin.InfoSite"/></param>
        public static int Configure(string path, IntPtr infoSitePtr)
        {
            GetStockQty = (GetStockQtyDelegate)Marshal.GetDelegateForFunctionPointer(new IntPtr(Marshal.ReadInt32(new IntPtr(infoSitePtr.ToInt32() + 4))), typeof(GetStockQtyDelegate));
            SetCategoryName = (SetCategoryNameDelegate)Marshal.GetDelegateForFunctionPointer(new IntPtr(Marshal.ReadInt32(new IntPtr(infoSitePtr.ToInt32() + 12))), typeof(SetCategoryNameDelegate));
            GetCategoryName = (GetCategoryNameDelegate)Marshal.GetDelegateForFunctionPointer(new IntPtr(Marshal.ReadInt32(new IntPtr(infoSitePtr.ToInt32() + 16))), typeof(GetCategoryNameDelegate));
            SetIndustrySector = (SetIndustrySectorDelegate)Marshal.GetDelegateForFunctionPointer(new IntPtr(Marshal.ReadInt32(new IntPtr(infoSitePtr.ToInt32() + 20))), typeof(SetIndustrySectorDelegate));
            GetIndustrySector = (GetIndustrySectorDelegate)Marshal.GetDelegateForFunctionPointer(new IntPtr(Marshal.ReadInt32(new IntPtr(infoSitePtr.ToInt32() + 24))), typeof(GetIndustrySectorDelegate));
            AddStock = (AddStockDelegate)Marshal.GetDelegateForFunctionPointer(new IntPtr(Marshal.ReadInt32(new IntPtr(infoSitePtr.ToInt32() + 20))), typeof(AddStockDelegate));
            MessageBox.Show(GetStockQty().ToString());
            return 1;
        }

        /// <summary>
        /// GetRecentInfo function is optional, used only by real-time plugins 
        /// </summary>
        public static RecentInfo GetRecentInfo(string ticker)
        {
            return new RecentInfo();
        }

        /// <summary>
        /// New API function, optional, only for RT plugins
        /// </summary>
        public static int IsBackfillComplete(string ticker)
        {
            return 1;
        }

        /// <summary>
        /// GetSymbolLimit function is optional, used only by real-time plugins
        /// </summary>
        public static int GetSymbolLimit()
        {
            return 1;
        }

        /// <summary>
        /// GetStatus function is optional, used mostly by few real-time plugins
        /// </summary>
        /// <param name="statusPtr">A pointer to <see cref="AmiBrokerPlugin.PluginStatus"/></param>
        public static int GetStatus(IntPtr statusPtr)
        {
            switch (Status)
            {
                case StatusCode.OK:
                    SetStatus(statusPtr, StatusCode.OK, Color.LightGreen, "OK", "Plugin works");
                    break;
                case StatusCode.Wait:
                    SetStatus(statusPtr, StatusCode.Wait, Color.LightBlue, "WAIT", "Wait a sec...");
                    break;
                case StatusCode.Error:
                    SetStatus(statusPtr, StatusCode.Error, Color.Red, "ERR", "An error occured");
                    break;
                default:
                    SetStatus(statusPtr, StatusCode.Unknown, Color.LightGray, "Ukno", "Unknown status");
                    break;
            }

            return 1;
        }

        /// <summary>
        /// SetTimeBase function is called when user is changing base time interval in File->Database Settings
        /// </summary>
        public static int SetTimeBase(int periodicity)
        {
            return periodicity >= (int)Periodicity.OneHour && periodicity <= (int)Periodicity.EndOfDay ? 1 : 0;
        }

        /// <summary>
        /// Notify function (optional) is called when database is loaded, unloaded
        /// settings are changed, or right mouse button in the plugin status area is clicked
        /// </summary>
        public static int Notify(ref PluginNotification notifyData)
        {
            if (MainWnd == IntPtr.Zero)
            {
                MainWnd = notifyData.MainWnd;
            }

            if (notifyData.Reason == PluginNotificationReason.StatusRightClick)
            {
                MessageBox.Show(GetStockQty().ToString());
            }

            return 1;
        }

        #endregion

        #region Optimizer Plugin API

        /////////////////////////////////////////////////////////////////////////
        // OPTIMIZER PLUGIN API
        /////////////////////////////////////////////////////////////////////////

        //public static int OptimizerInit(ref OptimizeParams optimizeParams)
        //{
        //    return 1;
        //}

        //public delegate double EvaluateFuncDelegate(IntPtr param);

        //public static int OptimizerRun(ref OptimizeParams optimizeParams, EvaluateFuncDelegate evaluateFunc, IntPtr context)
        //{
        //    return 1;
        //}

        //public static int OptimizerFinalize(ref OptimizeParams optimizeParams)
        //{
        //    return 1;
        //}

        //public static int OptimizerSetOption(string param, AmiVar newValue)
        //{
        //    return 1;
        //}

        #endregion
    }
}
